package com.example.java_chatroom.controller;

import com.example.java_chatroom.model.*;
import com.example.java_chatroom.service.MessageService;
import com.example.java_chatroom.service.MessageSessionService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.List;

@Component
public class WebSocketController extends TextWebSocketHandler {
    @Autowired
    private MessageSessionService messageSessionService;

    @Autowired
    private OnlineUserManager onlineUserManager;

    @Autowired
    private MessageService messageService;

    private ObjectMapper objectMapper=new ObjectMapper();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("[websocketController]连接成功");
        User user =(User) session.getAttributes().get("user");
//        此处提供的API是一个getAttributes这样的方法，返回的是一个Map
//        然后通过Map的get方法获取到key对应的value
        if(user==null){
            return;
        }
        System.out.println("获取到的userId"+user.getUserId());
//        把键值对存起来
        onlineUserManager.online(user.getUserId(),session);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println("[websocketController]收到消息"+message.toString());

//        1、先获取当前用户的信息，后需要进行消息转发
        User user =(User) session.getAttributes().get("user");
        if(user==null){
            System.out.println("[WebSocketController]user==null!未登录用户，无法进行消息转发");
            return;
        }
//        2、针对请求进行解析,把json格式的字符串，转成一个java对象
        MessageRequest request=objectMapper.readValue(message.getPayload(), MessageRequest.class);
        if(request.getType().equals("message")){
            //进行消息转发
            transferMessage(user,request);
        }else{
            System.out.println("[WebSocketController]request.type有误！"+message.getPayload());
        }

    }

//    完成消息实际的转发操作
//    第一个参数就表示这个要转发的消息，从谁，哪来的

    private void transferMessage(User fromUser, MessageRequest request) throws IOException {
//        1、先构造一个待转发的响应对象，MessageRespone
        MessageResponse response=new MessageResponse();
        response.setType("message");
        response.setFromId(fromUser.getUserId());
        response.setFromName(fromUser.getUsername());
        response.setSessionId(request.getSessionId());
        response.setContent(request.getContent());
//        把这个java对象转换成字符串
        String respJson=objectMapper.writeValueAsString(response);
        System.out.println("[transferMessage]responseJson"+respJson);
//        2、根据请求中的sessionId,获取到这个MessageSession里都有哪些用户，通过查询数据库知道
        List<Friend> friends=messageSessionService.getFriendsBySessionId(response.getSessionId(),fromUser.getUserId());
//        上诉会把当前发消息的用户排除掉，最终转发的时候，则需要也把发消息的人也发一遍
//        把当前用户也添加到上述List里面
        Friend myself=new Friend();
        myself.setFriendId(fromUser.getUserId());
        myself.setFriendName(fromUser.getUsername());
        friends.add(myself);

//        3、循环遍历上诉的这个列表，给这个列表中的每个用户都发一条响应消息
//        这里除了给查询到的好友们发, 也要给自己也发一个. 方便实现在自己的客户端上显示自己发送的消息
//        一个会话中, 可能有多个用户(群聊). 虽然客户端是没有支持群聊的(前端写起来相对麻烦), 后端无论是 API 还是 数据库//
//        都是支持群聊的. 此处的转发逻辑也一样让它支持群聊.

        for (Friend friend:friends) {
//        知道了每个用户的userId，进一步的查询刚才准备好的OnlineUserManager，就知道了对应的WebSocketSession
//        从而进行发送消息
            WebSocketSession webSocketSession= onlineUserManager.getSession(friend.getFriendId());
            if(webSocketSession==null){
//                如果该用户未在线，则不发送
                continue;
            }
            webSocketSession.sendMessage(new TextMessage(respJson));
        }


//        4、转发的消息，还需要放到数据库里，后续用户如果下线之后，重新上线，还可以通过历史消息的方式拿到之前的消息
//        需要往message中写入一条记录
        Message message=new Message();
        message.setFromId(fromUser.getUserId());
        message.setSessionId(request.getSessionId());
        message.setContent(request.getContent());
//        向自增主键，还有事件这样的属性，都可以让SQL在数据库中生成
        messageService.add(message);

    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("[websocketController]连接异常"+exception.toString());

        User user =(User) session.getAttributes().get("user");
        if(user==null){
            return;
        }
        onlineUserManager.offline(user.getUserId(),session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.out.println("[websocketController]连接关闭"+status.toString());
//session.getAttributes()通常是一个map类型类似于hash.get("user")
        User user =(User) session.getAttributes().get("user");
        onlineUserManager.offline(user.getUserId(), session);
    }
}
